const path = require("path");
const crypto = require("crypto");
const fse = require("fs-extra");
const cheerio = require("cheerio");
const mime = require("mime-types");
const { compressBuffer, compress } = require("./compress");

/** 是否压缩 */
const isCompress = false;

// const DEFAULT_DIST = path.resolve("./dist");
const DEFAULT_DIST = "";
const IMAGE_DIR = "images";

function splitPath(filePath) {
  const matches = filePath.match(/([^/]+)\.([^.]+)$/);
  const [, fileName = "", ext = ""] = matches || [];
  return {
    fileName,
    ext,
  };
}

function getSources(dir) {
  const result = new Map();
  const dirs = fse.readdirSync(dir);
  dirs.forEach((name) => {
    const filePath = path.resolve(dir, name);
    const stat = fse.statSync(filePath);
    if (stat.isFile()) {
      const { ext, fileName } = splitPath(name);
      if (["html", "htm"].indexOf(ext) > -1) {
        result.set(fileName, filePath);
      }
    }
  });
  return result;
}

function getMd5(str) {
  return crypto.createHash("md5").update(str).digest("hex");
}

async function covertBase64ToImg(htmlName, base64, outDir) {
  const { imgExtension, base64Img } = normalizeBase64(base64);
  const fileName = `${getMd5(base64Img).substring(0, 7)}.${imgExtension}`;
  const distPath = path.join(outDir, htmlName);
  const imagesPath = path.join(distPath, IMAGE_DIR);
  const imageName = path.join(imagesPath, fileName);
  const filePathRel = path.join(IMAGE_DIR, fileName);

  if (isCompress) {
    fse.ensureDirSync(imagesPath);
    fse.writeFileSync(imageName, base64Img, { encoding: "base64" }); 
    const compressedData = await compress([imageName]);
    if (compressedData.length) {
      const { data, sourcePath } = compressedData[0]
      fse.writeFileSync(imageName, data)
    }
  } else {
    fse.ensureDirSync(imagesPath);
    fse.writeFileSync(imageName, base64Img, { encoding: "base64" });
  }

  return filePathRel;
}

function normalizeBase64(base64) {
  const reMime = /[^:]\w+\/[\w-+\d.]+(?=;|,)/;
  const matches = base64.match(reMime);
  let mimetype = "image/png";
  if (matches && matches[0]) {
    mimetype = matches[0];
  }
  const imgExtension = mime.extension(mimetype);
  if (!imgExtension) {
    throw new Error(`未识别的mimetype:${mimetype}`);
  }
  const base64Img = base64.split(";base64,").pop() || "";
  if (!base64Img) {
    throw new Error("图片src或者格式不对");
  }
  return {
    mimetype,
    imgExtension,
    base64Img,
  };
}

async function covertHtml(source, outDir = DEFAULT_DIST) {
  let sources = new Map();
  const sourceStat = fse.statSync(source);
  if (sourceStat.isFile()) {
    const { fileName, ext } = splitPath(source);
    if (["html", "htm"].indexOf(ext) > -1) {
      sources.set(fileName, source);
    } else {
      throw new Error(
        `需要转换的html文件格式不支持，当前${source}文件格式为${ext}`
      );
    }
  } else if (sourceStat.isDirectory()) {
    sources = getSources(source);
  } else {
    throw new Error(`当前需要转换的路径${source}不存在请检查路径是否正确!`);
  }

  for (const [name, file] of sources.entries()) {
    const html = fse.readFileSync(file, "utf-8");
    const $ = cheerio.load(html);
    $("img").each(async function () {
      const img = $(this);
      const base64 = img.attr("src");
      if (base64) {
        const url = await covertBase64ToImg(name, base64, outDir);
        img.attr("src", url);
      }
    });
    const covertHtmlStr = $.html();
    const distPath = path.join(outDir, name);
    const htmlPath = path.resolve(distPath, `${name}.html`);
    fse.ensureDirSync(distPath);
    fse.writeFileSync(htmlPath, covertHtmlStr, { encoding: "utf-8" });
  }
}

module.exports = covertHtml;
